Una guía completa sobre el Intercambio de Recursos de Origen Cruzado (CORS), que cubre la configuración, las implicaciones de seguridad y las mejores prácticas para desarrolladores.
Intercambio de Recursos de Origen Cruzado (CORS): Configuración y Mejores Prácticas de Seguridad
En el mundo del desarrollo web, la seguridad es primordial. Un aspecto crítico de la seguridad web es gestionar cómo las páginas web de un origen pueden acceder a recursos de un origen diferente. Aquí es donde entra en juego el Intercambio de Recursos de Origen Cruzado (CORS). CORS es una característica de seguridad del navegador que restringe a las páginas web la realización de solicitudes a un dominio diferente al que sirvió la página web. Este mecanismo existe para evitar que sitios web maliciosos accedan a datos sensibles. Este artículo proporciona una guía completa sobre CORS, cubriendo su configuración, implicaciones de seguridad y mejores prácticas.
Entendiendo la Política del Mismo Origen
CORS se basa en el fundamento de la Política del Mismo Origen (Same-Origin Policy), un mecanismo de seguridad fundamental implementado por los navegadores web. La política del mismo origen restringe a las páginas web la realización de solicitudes a un dominio diferente al que sirvió la página web. Se considera que dos URL tienen el mismo origen si tienen el mismo protocolo (p. ej., HTTP o HTTPS), host (p. ej., example.com) y puerto (p. ej., 80 o 443). Por ejemplo:
http://example.comyhttp://example.com/pathson del mismo origen.http://example.comyhttps://example.comson de orígenes diferentes (protocolos diferentes).http://example.comyhttp://www.example.comson de orígenes diferentes (hosts diferentes).http://example.com:80yhttp://example.com:8080son de orígenes diferentes (puertos diferentes).
La política del mismo origen está diseñada para prevenir ataques de Cross-Site Scripting (XSS), donde un sitio web malicioso inyecta scripts en un sitio web de confianza para robar datos del usuario o realizar acciones no autorizadas. Sin la política del mismo origen, un sitio web malicioso podría acceder potencialmente a la información de su cuenta bancaria si estuviera conectado a su portal de banca en línea en otra pestaña.
¿Qué es el Intercambio de Recursos de Origen Cruzado (CORS)?
Aunque la política del mismo origen es crucial para la seguridad, también puede ser restrictiva en escenarios legítimos donde los sitios web necesitan acceder a recursos de diferentes orígenes. Por ejemplo, una aplicación web alojada en example.com podría necesitar obtener datos de una API alojada en api.example.net. CORS proporciona un mecanismo para eludir la política del mismo origen de manera controlada, permitiendo que las páginas web realicen solicitudes de origen cruzado cuando el servidor lo autorice explícitamente.
CORS funciona agregando encabezados HTTP a la respuesta del servidor, indicando qué orígenes tienen permitido acceder al recurso. El navegador luego verifica estos encabezados y bloquea la solicitud si el origen de la página web que realiza la solicitud no está permitido.
Cómo Funciona CORS: Los Encabezados HTTP
CORS se basa en encabezados HTTP específicos para facilitar las solicitudes de origen cruzado. Aquí están los encabezados clave involucrados:
1. Origin (Encabezado de Solicitud)
El encabezado Origin es enviado por el navegador en las solicitudes de origen cruzado. Indica el origen (protocolo, host y puerto) de la página web que realiza la solicitud. Por ejemplo:
Origin: http://example.com
2. Access-Control-Allow-Origin (Encabezado de Respuesta)
El encabezado Access-Control-Allow-Origin es el más importante en CORS. Especifica qué orígenes tienen permitido acceder al recurso. Puede tener uno de los siguientes valores:
- Un origen específico: Por ejemplo,
Access-Control-Allow-Origin: http://example.compermite solo solicitudes desdehttp://example.com. *(comodín):Access-Control-Allow-Origin: *permite solicitudes desde cualquier origen. Esto debe usarse con precaución, ya que deshabilita efectivamente la política del mismo origen para ese recurso.
Ejemplo:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (Encabezado de Respuesta)
El encabezado Access-Control-Allow-Methods especifica los métodos HTTP (p. ej., GET, POST, PUT, DELETE) que están permitidos en la solicitud de origen cruzado. Esto es necesario para las solicitudes preflight (explicadas a continuación).
Ejemplo:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (Encabezado de Respuesta)
El encabezado Access-Control-Allow-Headers especifica los encabezados HTTP que están permitidos en la solicitud de origen cruzado. Esto también es necesario para las solicitudes preflight.
Ejemplo:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (Encabezado de Respuesta)
El encabezado Access-Control-Allow-Credentials especifica si el navegador debe incluir credenciales (p. ej., cookies, encabezados de autorización) en la solicitud de origen cruzado. Puede tener uno de dos valores: true o false. Si se establece en true, el encabezado Access-Control-Allow-Origin no puede establecerse en *. Debe ser un origen específico.
Ejemplo:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (Encabezado de Respuesta)
El encabezado Access-Control-Max-Age especifica el número de segundos que el navegador puede almacenar en caché los resultados de la solicitud preflight. Esto puede mejorar el rendimiento al reducir el número de solicitudes preflight.
Ejemplo:
Access-Control-Max-Age: 3600
Solicitudes Simples vs. Solicitudes Preflight
CORS distingue entre dos tipos de solicitudes de origen cruzado: solicitudes simples y solicitudes preflight.
Solicitudes Simples
Una solicitud simple es una solicitud que cumple con los siguientes criterios:
- El método es
GET,HEADoPOST. - Si el método es
POST, el encabezadoContent-Typees uno de los siguientes:application/x-www-form-urlencoded,multipart/form-dataotext/plain. - La solicitud no establece ningún encabezado personalizado (aparte de los establecidos automáticamente por el navegador).
Para las solicitudes simples, el navegador envía la solicitud directamente al servidor. El servidor luego responde con los encabezados CORS apropiados. Si se permite el origen, el navegador procesa la respuesta. De lo contrario, el navegador bloquea la respuesta y lanza un error.
Solicitudes Preflight
Una solicitud preflight es enviada por el navegador antes de realizar la solicitud de origen cruzado real si la solicitud no cumple los criterios para una solicitud simple. Esto ocurre típicamente cuando la solicitud utiliza un método diferente a GET, HEAD o POST, o cuando la solicitud establece encabezados personalizados.
La solicitud preflight es una solicitud OPTIONS que incluye los siguientes encabezados:
Origin: El origen de la página web que realiza la solicitud.Access-Control-Request-Method: El método HTTP que se utilizará en la solicitud real.Access-Control-Request-Headers: Una lista separada por comas de los encabezados personalizados que se utilizarán en la solicitud real.
El servidor luego responde con los siguientes encabezados:
Access-Control-Allow-Origin: El origen que tiene permitido acceder al recurso.Access-Control-Allow-Methods: Los métodos HTTP que están permitidos en la solicitud de origen cruzado.Access-Control-Allow-Headers: Los encabezados HTTP que están permitidos en la solicitud de origen cruzado.Access-Control-Max-Age: El número de segundos que el navegador puede almacenar en caché los resultados de la solicitud preflight.
Si el servidor responde con los encabezados CORS apropiados, el navegador procede con la solicitud de origen cruzado real. De lo contrario, el navegador bloquea la solicitud y lanza un error.
Ejemplos de Configuración de CORS
La implementación de CORS varía según la tecnología del lado del servidor que esté utilizando. Aquí hay algunos ejemplos para lenguajes y frameworks comunes del lado del servidor:
Node.js con Express
Usar el middleware cors es un enfoque común para configurar CORS en Node.js con Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Habilitar CORS para todos los orígenes
app.use(cors());
// Habilitar CORS para un origen específico
// app.use(cors({ origin: 'http://example.com' }));
// Habilitar CORS con opciones
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python con Flask
Puede usar la extensión Flask-CORS para configurar CORS en Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Habilitar CORS para todos los orígenes
CORS(app)
# Habilitar CORS para orígenes específicos
# CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java con Spring Boot
Spring Boot proporciona varias formas de configurar CORS. Un enfoque es usar la anotación @CrossOrigin:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Origen específico
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Configuración global de CORS (usando WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
En PHP, puede establecer los encabezados CORS directamente en su script:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
Consideraciones de Seguridad de CORS
Aunque CORS permite solicitudes de origen cruzado, es crucial comprender las implicaciones de seguridad e implementarlo correctamente para evitar vulnerabilidades.
1. Evite Usar Access-Control-Allow-Origin: * en Producción
Usar el comodín * en el encabezado Access-Control-Allow-Origin permite solicitudes desde cualquier origen, deshabilitando efectivamente la política del mismo origen para ese recurso. Esto puede exponer su API a sitios web maliciosos que pueden robar datos de usuario o realizar acciones no autorizadas. En su lugar, especifique los orígenes exactos que tienen permitido acceder al recurso. Por ejemplo, si su aplicación web está alojada en example.com y necesita acceder a una API alojada en api.example.com, establezca el encabezado en Access-Control-Allow-Origin: http://example.com.
Ejemplo global: Imagine una API de servicios financieros que establece Access-Control-Allow-Origin: *. Un sitio web malicioso podría entonces realizar solicitudes a esta API en nombre de un usuario autenticado, transfiriendo fondos potencialmente sin el conocimiento del usuario.
2. Valide el Encabezado Origin en el Servidor
Incluso si especifica una lista de orígenes permitidos, es importante validar el encabezado Origin en el servidor para evitar que los atacantes falsifiquen el origen. Un atacante podría enviar una solicitud con un encabezado Origin falsificado para eludir las verificaciones de CORS. Para mitigar esto, compare el encabezado Origin con una lista de orígenes de confianza en el lado del servidor. Si el origen no está en la lista, rechace la solicitud.
Ejemplo global: Considere una plataforma de comercio electrónico. Un atacante podría intentar imitar el Origin de una tienda legítima para acceder a datos sensibles de clientes desde la API de la plataforma de comercio electrónico.
3. Tenga Cuidado con Access-Control-Allow-Credentials: true
Si establece Access-Control-Allow-Credentials: true, el encabezado Access-Control-Allow-Origin no puede establecerse en *. Debe ser un origen específico. Esto se debe a que permitir credenciales desde cualquier origen puede crear un riesgo de seguridad, ya que podría permitir que sitios web maliciosos accedan a datos de usuario si logran engañar a un usuario para que visite su sitio mientras también está autenticado en el sitio web objetivo. Esta configuración es importante cuando se trabaja con cookies o encabezados de autorización.
Ejemplo global: Una plataforma de redes sociales que permite solicitudes de origen cruzado con credenciales requiere una gestión cuidadosa para evitar el acceso no autorizado a las cuentas de los usuarios.
4. Configure Adecuadamente Access-Control-Allow-Methods y Access-Control-Allow-Headers
Permita solo los métodos y encabezados HTTP que sean necesarios para las solicitudes de origen cruzado. Si solo necesita permitir solicitudes GET y POST, no permita PUT, DELETE u otros métodos. De manera similar, permita solo los encabezados específicos que su aplicación necesita. Las configuraciones demasiado permisivas pueden aumentar el riesgo de ataques.
Ejemplo Global: Un sistema CRM solo debe exponer los endpoints de API y encabezados necesarios a las integraciones de terceros autorizadas, minimizando la superficie de ataque.
5. Use HTTPS para una Comunicación Segura
Utilice siempre HTTPS para una comunicación segura entre el navegador y el servidor. HTTPS cifra los datos transmitidos entre el navegador y el servidor, evitando la intercepción y los ataques de tipo "man-in-the-middle". Usar HTTP puede exponer datos sensibles a los atacantes, incluso si CORS está configurado correctamente.
Ejemplo Global: Las aplicaciones de atención médica deben usar HTTPS para proteger los datos de los pacientes transmitidos entre diferentes orígenes.
6. Política de Seguridad de Contenido (CSP)
Aunque no está directamente relacionada con CORS, la Política de Seguridad de Contenido (CSP) es otro mecanismo de seguridad importante que puede ayudar a prevenir ataques XSS. CSP le permite definir una lista blanca de fuentes desde las cuales el navegador tiene permitido cargar recursos. Esto puede ayudar a evitar que los atacantes inyecten scripts maliciosos en su sitio web, incluso si logran eludir otras medidas de seguridad.
Ejemplo global: Las instituciones financieras a menudo emplean políticas de CSP estrictas para limitar las fuentes de contenido que se cargan en sus portales de banca en línea, reduciendo el riesgo de ataques XSS.
Problemas Comunes de CORS y Solución de Problemas
Los errores de CORS pueden ser frustrantes de depurar. Aquí hay algunos problemas comunes y cómo solucionarlos:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Este es el error de CORS más común. Indica que el servidor no está devolviendo el encabezado Access-Control-Allow-Origin en su respuesta. Asegúrese de que el servidor esté configurado para enviar los encabezados CORS correctos para el origen de la página web que realiza la solicitud. Verifique dos veces el código del lado del servidor y los archivos de configuración.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
Este error indica que la solicitud preflight falló. Esto puede suceder si el servidor no responde a las solicitudes OPTIONS o si el servidor devuelve un código de estado de error (p. ej., 404, 500) en respuesta a la solicitud preflight. Asegúrese de que su servidor esté configurado para manejar solicitudes OPTIONS y que esté devolviendo un código de estado 200 OK.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
Este error ocurre cuando intenta enviar credenciales (p. ej., cookies) en una solicitud de origen cruzado y el encabezado Access-Control-Allow-Origin está establecido en *. Como se mencionó anteriormente, no puede usar el comodín * al enviar credenciales. Debe especificar el origen exacto que tiene permitido acceder al recurso.
4. Almacenamiento en Caché del Navegador
Los navegadores pueden almacenar en caché las respuestas de CORS, lo que puede llevar a un comportamiento inesperado si la configuración de CORS cambia. Para evitar problemas de caché, establezca el encabezado Cache-Control en la respuesta a no-cache, no-store o max-age=0. También puede usar el encabezado Access-Control-Max-Age para controlar durante cuánto tiempo el navegador almacena en caché los resultados de la solicitud preflight.
Alternativas a CORS
Aunque CORS es la forma estándar de habilitar las solicitudes de origen cruzado, existen algunas alternativas que puede considerar en ciertos escenarios:
1. JSON con Relleno (JSONP)
JSONP es una técnica que utiliza la etiqueta <script> para eludir la política del mismo origen. JSONP funciona envolviendo los datos JSON en una llamada a una función de JavaScript. El navegador luego ejecuta la función de JavaScript, pasando los datos JSON como argumento. JSONP es más simple de implementar que CORS, pero tiene algunas limitaciones. Solo admite solicitudes GET y es menos seguro que CORS.
2. Proxy Inverso
Un proxy inverso es un servidor que se sitúa frente a su servidor de API y le reenvía las solicitudes. El proxy inverso se puede configurar para agregar los encabezados CORS necesarios a la respuesta, ocultando efectivamente las solicitudes de origen cruzado del navegador. Este enfoque puede ser útil si no tiene control sobre el servidor de la API o si desea simplificar la configuración de CORS.
Conclusión
El Intercambio de Recursos de Origen Cruzado (CORS) es un mecanismo de seguridad crucial que permite a las páginas web acceder a recursos de diferentes orígenes de manera controlada. Comprender cómo funciona CORS e implementarlo correctamente es esencial para construir aplicaciones web seguras y confiables. Siguiendo las mejores prácticas descritas en este artículo, puede gestionar eficazmente CORS y proteger sus API del acceso no autorizado.
Recuerde siempre priorizar la seguridad al configurar CORS. Evite el uso de comodines, valide el encabezado Origin y use HTTPS para una comunicación segura. Al tomar estas precauciones, puede asegurarse de que sus aplicaciones web estén protegidas contra ataques de sitios cruzados.
Esta guía completa proporciona una base sólida para comprender CORS. Consulte siempre la documentación oficial de su tecnología específica del lado del servidor para obtener la información más actualizada y las mejores prácticas. Manténgase informado sobre las amenazas de seguridad emergentes y adapte su configuración de CORS en consecuencia.